package com.pphh.demo.consumer;

import com.alibaba.csp.sentinel.concurrent.NamedThreadFactory;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.SentinelRpcException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import java.util.Collections;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * A example shows how to control the speed of dubbo rpc calls by concurrent threads
 * this example make reference to sentinel's demo examples.
 * https://github.com/alibaba/Sentinel
 *
 * @author pphh
 * @date 2019/1/18
 */
public class ConsumerBootstrap {

    private static final String RES_KEY = "com.pphh.demo.DemoService:sayHello(java.lang.String)";

    private static final ExecutorService pool = Executors.newFixedThreadPool(10,
            new NamedThreadFactory("dubbo-consumer-pool"));

    public static void main(String[] args) {
        initFlowRule();

        AnnotationConfigApplicationContext consumerContext = new AnnotationConfigApplicationContext();
        consumerContext.register(ConsumerConfiguration.class);
        consumerContext.refresh();

        DemoServiceRef greetingsService = consumerContext.getBean(DemoServiceRef.class);

        for (int i = 0; i < 15; i++) {
            pool.submit(() -> {
                try {
                    String message = greetingsService.sayHello("michael");
                    System.out.println("Success: " + message);
                } catch (SentinelRpcException ex) {
                    System.out.println("Blocked by sentinel, concurrent thread limit = 5, which is controlled on consumer side");
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            });
        }

        pool.shutdown();
    }

    /**
     * control the flow by number of concurrent thread
     * RuleConstant.FLOW_GRADE_THREAD
     */
    private static void initFlowRule() {
        FlowRule flowRule = new FlowRule();
        flowRule.setResource(RES_KEY);
        flowRule.setCount(5);
        flowRule.setGrade(RuleConstant.FLOW_GRADE_THREAD);
        flowRule.setLimitApp("default");
        FlowRuleManager.loadRules(Collections.singletonList(flowRule));
    }
}
